package com.atguigu.juc.study.chapter14.stampedlock;

import lombok.Data;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.StampedLock;

/**
 *  StampedLock = ReentrantReadWriteLock + 读的过程中也允许获取写锁介入
 *
 * @author : leimingchao
 * @date Date : 2022年06月22日 13:29
 */
@Data
public class MyStampedLockResource {

    static int number = 37;

    static StampedLock stampedLock = new StampedLock();

    public void write() {

        long stamp = stampedLock.writeLock();

        System.out.println(Thread.currentThread().getName() + "\t" + "写线程准备修改");

        try {
            number = number + 13;
        } finally {
            stampedLock.unlockWrite(stamp);
        }

        System.out.println(Thread.currentThread().getName() + "\t" + "写线程结束修改");
    }

    /**
     * 悲观读,读没有完成时候写锁无法获得锁
     */
    public void read() {
        long stamp = stampedLock.readLock();
        System.out.println(Thread.currentThread().getName() + "\t" + "come in readLock code block, 4 seconds continue...");
        for (int i = 0; i < 4; i++) {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName() + "\t" + " 正在读取中.....");
        }

        try {

            int result = number;
            System.out.println(Thread.currentThread().getName() + "\t" + " 获得成员变量值 result：" + result);
            System.out.println(Thread.currentThread().getName() + "\t" + " 写线程没有修改成功，读锁时候写锁无法介入，传统的读写互斥");

        } finally {
            stampedLock.unlockRead(stamp);
        }
    }

    /**
     * 乐观读，读的过程中也允许获取写锁介入
     */
    public void tryOptimisticRead() {

        long stamp = stampedLock.tryOptimisticRead();

        int result = number;

        //故意间隔4秒钟，很乐观认为读取中没有其他线程修改过number值，具体考判断
        System.out.println("4秒前:stampedLock.validate()值(true：无修改，false：有修改)" + "\t" + stampedLock.validate(stamp));
        for (int i = 0; i < 4; i++) {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName() + "\t" + " 正在读取中....." + i + "秒后stampedLock.validate()值(true：无修改，false：有修改)" + "\t" + stampedLock.validate(stamp));
        }

        if (!stampedLock.validate(stamp)) {
            System.out.println("有人修改过-----有写操作");
            stamp = stampedLock.readLock();

            try {
                System.out.println("从乐观读升级为悲观读");
                result = number;

            } finally {
                stampedLock.unlockRead(stamp);
            }
        }

        System.out.println(Thread.currentThread().getName() + "\t" + "finally value:" + result);
    }
}
